/*
 * ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
 */

package org.modelcc.language.metamodel;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.modelcc.AssociativityType;
import org.modelcc.SeparatorPolicy;
import org.modelcc.lexer.recognizer.PatternRecognizer;
import org.modelcc.metamodel.Evaluator;
import org.modelcc.metamodel.ModelElement;

/**
 * Language model element.
 * 
 * @author Luis Quesada (lquesada@modelcc.org) & Fernando Berzal (berzal@modelcc.org)
 */
public class LanguageElement extends ModelElement<LanguageMember> implements Serializable 
{
    /**
     * Prefix.
     */
    private List<PatternRecognizer> prefix;

    /**
     * Suffix.
     */
    private List<PatternRecognizer> suffix;

    /**
     * Separator.
     */
    private List<PatternRecognizer> separator;

    /**
     * Associativity type.
     */
    private AssociativityType associativity;

    /**
     * Setup method.
     */
    private String setupMethod;

    /**
     * Constraint methods.
     */
    private List<String> constraintMethods;


    /**
     * Positions.
     */
    private Map<LanguageMember, MemberPositionMetadata> positions;
    
    /** 
     * Evaluator.
     */
    private Evaluator evaluator;
    
    /**
     * Constructor.
     * @param elementClass the element class
     * @param associativity the associativity
     * @param prefix the prefix
     * @param suffix the suffix
     * @param separator the default separator
     * @param setupMethod the setup method
     * @param constraintMethod the constraint methods
     * @param evaluator the evaluator
     */
    public LanguageElement(
    		Class elementClass,
    		AssociativityType associativity,
    		List<PatternRecognizer> prefix,
    		List<PatternRecognizer> suffix,
    		List<PatternRecognizer> separator,
    		String setupMethod,
    		List<String> constraintMethods,
    		Evaluator evaluator) 
    {
    	super(elementClass);
    	
        this.prefix = prefix;
        if (prefix == null)
            this.prefix = new ArrayList<PatternRecognizer>();
        this.suffix = suffix;
        if (suffix == null)
            this.suffix = new ArrayList<PatternRecognizer>();
        this.separator = separator;
        if (separator == null)
            this.separator = new ArrayList<PatternRecognizer>();
        
        this.associativity = associativity;

        this.setupMethod = setupMethod;
        this.constraintMethods = constraintMethods;
        
        this.evaluator = evaluator;
    }


    // Delimiters
    
    public List<PatternRecognizer> getPrefix() {
        return Collections.unmodifiableList(prefix);
    }

    public List<PatternRecognizer> getSuffix() {
        return Collections.unmodifiableList(suffix);
    }

    public List<PatternRecognizer> getSeparator() {
        return Collections.unmodifiableList(separator);
    }

    public void setPrefix(List<PatternRecognizer> prefix) {
		this.prefix = prefix;
	}

	public void setSuffix(List<PatternRecognizer> suffix) {
		this.suffix = suffix;
	}

	public void setSeparator(List<PatternRecognizer> separator) {
		this.separator = separator;
	}

	// Setup method
	
    public String getSetupMethod() {
        return setupMethod;
    }

    // Constraint method
    
    public List<String> getConstraintMethods() {
        return Collections.unmodifiableList(constraintMethods);
    }

    // Associativity 
    
    public AssociativityType getAssociativity() {
        return associativity;
    }

    public void setAssociativity(AssociativityType associativity) {
		this.associativity = associativity;
	}

    // Position information
    
	public Map<LanguageMember, MemberPositionMetadata> getPositions() {
		return Collections.unmodifiableMap(positions);
	}

	public void setPositions(Map<LanguageMember, MemberPositionMetadata> positions) {
		this.positions = positions;
	}
	
	public void setPosition(LanguageMember thisMember,LanguageMember otherMember,int[] position,SeparatorPolicy separatorPolicy) {
		positions.put(thisMember,new MemberPositionMetadata(otherMember,position,separatorPolicy));
	}

	// Evaluator
	
    public Evaluator getEvaluator() {
    	return evaluator;
    }
}
